#include <phpx.h>
using namespace std;
using namespace php;

//声明方法
PHPX_FUNCTION(cpp_test);

//实现方法
PHPX_FUNCTION(cpp_test){
    long n = args[1].toInt();
    Array _array(retval);

    for(int i = 0;i < n; i++){
        _array.append(args[0]);
    }
}

/**
* #define PHPX_METHOD(c, m)       void c##_##m(Object &_this, Args &args, Variant &retval)
*/
PHPX_METHOD(CppClass,__construct)
{
	echo("%s __construct\n",_this.getClassName().c_str());

	//动态添加属性的
	Array array;
	array.append(1234);
	_this.set("name",array);
}

PHPX_METHOD(CppClass,test1)
{
    //读取全局变量
    Variant server = global("_SERVER");
    var_dump(server);
    if (server.isArray())
    {
        Variant shell = Array(server)["SHELL"];
        var_dump(shell);
    }
    auto name = _this.get("name");
    var_dump(name);
}

PHPX_METHOD(CppClass,test2)
{
	echo("test2");
}

/**
*
*/
PHPX_METHOD(CppClass,__get)
{
	echo("__get");
}
/**
* 把cpp中的方法绑定到php中是不行的！变通的方式是通过定义成员方法的形式进行的
* 
*/
PHPX_METHOD(CppClass,fncall)
{
	//auto fncall = []
	//{
		//var_dump(_this);
		//echo(_this.get("name"));
	//	echo("fncall");
	//};
	//var_dump(fncall);

	//_this.set("fncaller",fncall);

	retval = true;
}

/**
* 把php的方法通过变量传递都cpp中，是可行的
*/
PHPX_METHOD(CppClass,setFn)
{
	//if(_this.get("caller").isCallable()){
	//	_this.get("caller")();
	//}
	// Variant* fn = ;

	// if(is_callable(args[0])){
		// var_dump(args[0]);
	// }
	
	/**
	* 使用call方法调用php里面的方法
	*  有有参数和无参数两种
	*/
	call(_this.get("ccc"),args);

	//php::exec("setFn");

	//var_dump(_this);
}

/**
* 声明一个扩展
* #define PHPX_EXTENSION()        extern "C" { ZEND_DLEXPORT Extension* get_module(); } ZEND_DLEXPORT Extension* get_module()
* 使用c格式声明方法 get_module 使用cpp格式进行实现
*/
PHPX_EXTENSION()
{
	Extension *ext = new Extension("test","0.0.2");

	//在扩展中注册一个函数，全局的
	ext->registerFunction(PHPX_FN(cpp_test));
	
	/**
	* 前面的是方法的名称，可以是包含明明空间的
	* 名称会转换成小写的
	* 不能正常的注册命名空间 "\\CppTest\\test33"
	*/
	//ext->registerFunction("\\CppTest\\test33",cpp_test); //这种写法是不正确的
	ext->registerFunction("CppTest\\test33",cpp_test);

	ext->registerConstant("cons1",100);
	/*
	* 不能照着这个方式注册命名空间的！"\\CppTest\\cons2"
	* 名字空间的格式开头没有\
	*/
	//ext->registerConstant("\\CppTest\\cons2","hello world"); //这种写法是不正确的
	ext->registerConstant("CppTest\\cons2","hello world");

	//匿名函数
	ext->onStart = [ext]
	{
			//声明一个类
			Class *c = new Class("CppTest\\CppClass");
			//添加构造方法
			c->addMethod(PHPX_ME(CppClass,__construct),CONSTRUCT);
			//添加实例方法
			c->addMethod(PHPX_ME(CppClass,test1));
			//添加静态方法
			c->addMethod(PHPX_ME(CppClass,test2),STATIC);
			//c->addMethod(PHPX_ME(CppClass,test2),STATIC);
			//添加属性
			c->addProperty("age",10);
			//添加常量
			c->addConstant("VERSION","0.0.1");
			//静态属性的
			c->addProperty("status","ok",STATIC);

			//c->addMethod(PHPX_ME(CppClass,fncall));

			c->addMethod(PHPX_ME(CppClass,setFn));

			//注册魔术方法，是否可行??
			//ArgInfo(int required_num, bool return_reference = false) 
			//第一个参数就是方法必须的参数的个数，第二个是是否返回引用的
			ArgInfo *argInfo = new ArgInfo(1);
        	argInfo->add("name");

			//前面两个参数就是方法的名称，第三个参数就是方法的标识，第四个参数就是标记方法的参数和返回的信息
			c->addMethod(PHPX_ME(CppClass,__get),PUBLIC,argInfo);

			ext->registerClass(c);
	};

    ext->onShutdown = nullptr;
    ext->onBeforeRequest = nullptr;
    ext->onAfterRequest = nullptr;

	return ext;
}